#include "ServerUser.h"
#include <iostream>
#include <conio.h>
#include <WinSock2.h>
using namespace std;


ServerUser::ServerUser() : nconn(0)
{
	for(int i = 0; i < MAX_CONN; i++)
	{
		clt[i].par = this;
		clt[i].index = i;
	}
};

ServerUser::~ServerUser(void)
{
	endTalk();
}

bool ServerUser::init(int port, char* hostIp)
{
	sockSrv = socket(AF_INET, SOCK_STREAM, 0);

	if(sockSrv == INVALID_SOCKET)
	{
		printf("socket error\n");
		return false;
	}
	
	addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	//initAddr(PORT);

	//int err;

	if(bind(sockSrv, (SOCKADDR*)&addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
	{
		printf("bind error\n");
		return false;
	}

	if( listen(sockSrv, MAX_CONN) == SOCKET_ERROR)
	{
		printf("listen error\n");
		return false;
	}

	hServerThread = CreateThread(NULL, 0, waitConn, (LPVOID)this, 0, NULL);
	//waitConn((LPVOID)this);

	return true;
}


DWORD WINAPI waitConn(LPVOID lp)
{
	ServerUser* user = (ServerUser*) lp;
	int lenAddr = sizeof(SOCKADDR);
	while(true)
	{
		char sendBuff[LENGTH];
		//char recvBuff[LENGTH];
		//int nsend, nrecv;

		if(!user->nconn)
		{
			printf("waiting client...\n");
		}
		int ifreeConn = user->getFreeConn();
		if(ifreeConn != -1)
		{
			user->clt[ifreeConn].sock = accept(user->sockSrv, (SOCKADDR*)&user->clt[ifreeConn].addr/*Client*/, &lenAddr);
			user->nconn++;
			user->clt[ifreeConn].ok = true;

			//printf("%s is connected!\n", inet_ntoa(user->addr/*Client*/.sin_addr));
			sprintf(sendBuff, "%s is connected!\n", inet_ntoa(user->clt[ifreeConn].addr/*Client*/.sin_addr));
			user->sender(sendBuff);
			sprintf(sendBuff, "Welcome %s to here!\n", inet_ntoa(user->clt[ifreeConn].addr/*Client*/.sin_addr));
			send(user->clt[ifreeConn].sock, sendBuff, strlen(sendBuff), 0);
			//user->sender(sendBuff);
		}

		while(user->nconn >= MAX_CONN)
		{
			Sleep(10);
			continue;
		}
		Sleep(10);
	}
}

int ServerUser::getNumOfConn()
{
	return nconn;
}

void ServerUser::endTalk()
{
	for(int i = 0; i < MAX_CONN; i++)
	{
		endTalk(i);
	}
}

void ServerUser::endTalk(int i)
{
	closesocket(clt[i].sock);
	if(clt[i].ok)
	{
		clt[i].ok = false;
		nconn--;
	}
}

DWORD WINAPI wait_for_msg_per(LPVOID lp)
{
	Client *clt = (Client*)lp;
	ServerUser *server = (ServerUser*)clt->par;
	while(true)
	{
		if(!clt->ok)
		{
			Sleep(10);
			continue;
		}
		int nrecv;
		char recvBuff[LENGTH];
		nrecv = recv(clt->sock, recvBuff, LENGTH, 0);
		if(nrecv > 0)
		{
			recvBuff[nrecv] = 0;
			server->sender(recvBuff);
		}
		else if (nrecv == SOCKET_ERROR)
		{
			sprintf(recvBuff, "Disconnected from the %s!\n", inet_ntoa(clt->addr.sin_addr));
			server->sender(recvBuff);
			server->endTalk(clt->index);
		}
		Sleep(10);
	}
}

void ServerUser::reciver()
{
	//start listener for recive msg for per conntect
	for(int i = 0; i < MAX_CONN; i++)
	{
		hClientThread[i] = CreateThread(NULL, 0, wait_for_msg_per, &this->clt[i], NULL, NULL);

	}
}

int ServerUser::getFreeConn()
{
	for(int i = 0; i < MAX_CONN; i++)
		if(!clt[i].ok)
			return i;
	return -1;
}

bool ServerUser::sender(char *msg, int flag)
{
	bool ok = false;
	for(int i = 0; i < MAX_CONN; i++)
		if(clt[i].ok)
		{
			int nsend = send(clt[i].sock, msg, strlen(msg), 0);
			if(nsend == strlen(msg))
				ok = true;
		}
	if(flag == 0)
		printf("%s\n", msg);
	return ok;
}

void ServerUser::startTalk()
{
	while(!nconn)
	{
		Sleep(10);
		continue;
	}
	//recive from everyone except me
	reciver();

	//send msg to everyone except me
	while(true)
	{
		char sendBuff[LENGTH];
		sprintf(sendBuff, "%s: ", name);
		gets(sendBuff+strlen(sendBuff));

		if(!sender(sendBuff))
			printf("send error\n");
	}
	endTalk();
}